package xyz.yuzegod.megawalls.listener;

import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.api.event.NPCLeftClickEvent;
import org.bukkit.block.Block;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftWither;
import org.bukkit.entity.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.*;
import org.bukkit.inventory.ItemStack;
import xyz.yuzegod.megawalls.MegaWalls;
import xyz.yuzegod.megawalls.event.PlayerEnergyChangeEvent;
import xyz.yuzegod.megawalls.game.FakePlayer;
import xyz.yuzegod.megawalls.game.Game;
import xyz.yuzegod.megawalls.game.GamePlayer;
import xyz.yuzegod.megawalls.game.GameTeam;
import xyz.yuzegod.megawalls.game.team.TeamWither;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.List;

public class EntityListener extends BaseListener
{
    private final Game game;
    
    public EntityListener(final MegaWalls plugin) {
        super(plugin);
        this.game = plugin.getGame();
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onPotionSplash(final PotionSplashEvent e) {
        for (final LivingEntity entity : e.getAffectedEntities()) {
            if (entity instanceof Player && GamePlayer.get(entity.getUniqueId()).isSpectator()) {
                e.setCancelled(true);
            }
        }
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onEntitySpawn(final EntitySpawnEvent e) {
        if (!this.game.isStarted()) {
            e.setCancelled(true);
        }
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onCreatureSpawn(final CreatureSpawnEvent e) {
        if (this.game.isStarted() && e.getSpawnReason() == CreatureSpawnEvent.SpawnReason.CUSTOM) {
            return;
        }
        if (e.getEntity().hasMetadata(MegaWalls.getMetadataValue())) {
            return;
        }
        e.setCancelled(true);
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onEntityTarget(final EntityTargetEvent e) {
        if (!this.game.isStarted() || this.game.isOver() || (e.getTarget() instanceof Player && GamePlayer.get(e.getTarget().getUniqueId()).isSpectator())) {
            e.setCancelled(true);
        }
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onEntityExplode(final EntityExplodeEvent e) {
        if (!this.game.isStarted() || this.game.isOver()) {
            e.setCancelled(true);
            return;
        }
        if (this.game.isStarted()) {
            final List<Block> toRemove = new ArrayList<Block>();
            for (final Block block : e.blockList()) {
                if (this.game.isProtected(block.getLocation()) || this.game.isUnbreakable(block.getLocation())) {
                    toRemove.add(block);
                }
            }
            e.blockList().removeAll(toRemove);
            if (e.getEntity().hasMetadata(MegaWalls.getMetadataValue()) && e.getEntity() instanceof TNTPrimed) {
                e.blockList().clear();
            }
        }
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onNPCClick(final NPCLeftClickEvent e) {
        final GamePlayer gamePlayer = GamePlayer.get(e.getClicker().getUniqueId());
        if (gamePlayer==null){
            return;
        }
        if (gamePlayer.isSpectator()) {
            return;
        }
        final FakePlayer fakePlayer = FakePlayer.getFakePlayer(e.getNPC());
        if (fakePlayer != null) {
            final GamePlayer player = fakePlayer.getGamePlayer();
            if (gamePlayer.getGameTeam().isInTeam(player)) {
                e.setCancelled(true);
                return;
            }
            for (final ItemStack itemStack : fakePlayer.getDrops()) {
                e.getClicker().getWorld().dropItem(fakePlayer.getLocation(), itemStack);
            }
            gamePlayer.handleKill(player, e.getNPC().getEntity());
            fakePlayer.setKilled(true);
            fakePlayer.delete();
        }
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onEntityDamage(final EntityDamageEvent e) {
        if (CitizensAPI.getNPCRegistry().isNPC(e.getEntity())) {
            return;
        }
        if (e.getEntity() instanceof Player) {
            final Player player = (Player)e.getEntity();
            final GamePlayer gamePlayer = GamePlayer.get(e.getEntity().getUniqueId());
            if (gamePlayer.isSpectator()) {
                e.setCancelled(true);
                if (e.getCause() == EntityDamageEvent.DamageCause.SUFFOCATION) {
                    gamePlayer.getSpectatorTarget().tp();
                }
                return;
            }
            if (gamePlayer.isProtect()) {
                e.setCancelled(true);
                return;
            }
            if (this.game.isWaiting() || !this.game.isStarted()) {
                if (e.getCause() == EntityDamageEvent.DamageCause.VOID) {
                    player.teleport(this.game.getLobbyLocation());
                }
                e.setCancelled(true);
            }
        }
    }
    
    @EventHandler(priority = EventPriority.HIGH)
    public void onEntityDamageByEntity(final EntityDamageByEntityEvent e) {
        if (e.isCancelled()) {
            return;
        }
        if (e.getDamager().hasMetadata("CREEPER")) {
            e.setCancelled(true);
            return;
        }
        if (e.getDamager() instanceof Player) {
            final GamePlayer damager = GamePlayer.get(e.getDamager().getUniqueId());
            if (damager.isSpectator()) {
                e.setCancelled(true);
                return;
            }
            if (CitizensAPI.getNPCRegistry().isNPC(e.getEntity())) {
                return;
            }
            if (e.getEntity() instanceof Player) {
                final GamePlayer gamePlayer = GamePlayer.get(e.getEntity().getUniqueId());
                final GameTeam team = gamePlayer.getGameTeam();
                if (!this.game.isStarted()) {
                    return;
                }
                if (gamePlayer.isSpectator()) {
                    e.setCancelled(true);
                    return;
                }
                if (gamePlayer.isProtect()) {
                    e.setCancelled(true);
                    return;
                }
                if (team != null && team.isInTeam(damager)) {
                    e.setCancelled(true);
                    return;
                }
                gamePlayer.setLastDamage(damager, System.currentTimeMillis());
                damager.addEnergy(damager.getPlayerStats().getSelected().energyMelee(), PlayerEnergyChangeEvent.ChangeReason.MELLEE);
            }
            else if (e.getEntity().hasMetadata(MegaWalls.getMetadataValue())) {
                if (!(e.getEntity().getMetadata(MegaWalls.getMetadataValue()).get(0).value() instanceof GameTeam)) {
                    return;
                }
                final GameTeam gameTeam = (GameTeam)e.getEntity().getMetadata(MegaWalls.getMetadataValue()).get(0).value();
                if (gameTeam.isInTeam(GamePlayer.get(e.getDamager().getUniqueId()))) {
                    e.setCancelled(true);
                }
            }
        }
        else if (e.getDamager() instanceof Projectile) {
            final Projectile projectile = (Projectile)e.getDamager();
            if (projectile.getShooter() instanceof Player) {
                final GamePlayer shooter = GamePlayer.get(((Player)projectile.getShooter()).getUniqueId());
                if (shooter.isSpectator()) {
                    e.setCancelled(true);
                    return;
                }
                if (e.getEntity() instanceof Player) {
                    if (CitizensAPI.getNPCRegistry().isNPC(e.getEntity())) {
                        return;
                    }
                    final GamePlayer gamePlayer2 = GamePlayer.get(e.getEntity().getUniqueId());
                    final GameTeam team2 = gamePlayer2.getGameTeam();
                    if (!this.game.isStarted()) {
                        return;
                    }
                    if (gamePlayer2.isSpectator()) {
                        e.setCancelled(true);
                        return;
                    }
                    if (gamePlayer2.isProtect()) {
                        e.setCancelled(true);
                        return;
                    }
                    if (team2 != null && team2.isInTeam(shooter)) {
                        e.setCancelled(true);
                        return;
                    }
                    if (projectile.getType() == EntityType.ARROW) {
                        final Player player = gamePlayer2.getPlayer();
                        final double health = player.getHealth();
                        final Double damage = e.getFinalDamage();
                        if (!player.isDead()) {
                            final Double realHealth = health - damage.intValue();
                            final NumberFormat nf = NumberFormat.getInstance();
                            nf.setMaximumFractionDigits(1);
                            if (realHealth.intValue() > 0) {
                                shooter.sendMessage("§7" + player.getDisplayName() + "§e还剩§c" + nf.format(realHealth) + "§e血量！");
                            }
                        }
                    }
                    gamePlayer2.setLastDamage(shooter, System.currentTimeMillis());
                    if (!projectile.hasMetadata("NoAddEnergy")) {
                        shooter.addEnergy(shooter.getPlayerStats().getSelected().energyBow(), PlayerEnergyChangeEvent.ChangeReason.BOW);
                    }
                }
                else if (e.getEntity().hasMetadata(MegaWalls.getMetadataValue())) {
                    if (!(e.getEntity().getMetadata(MegaWalls.getMetadataValue()).get(0).value() instanceof GameTeam)) {
                        return;
                    }
                    final GameTeam gameTeam2 = (GameTeam)e.getEntity().getMetadata(MegaWalls.getMetadataValue()).get(0).value();
                    if (gameTeam2.isInTeam(GamePlayer.get(e.getDamager().getUniqueId()))) {
                        e.setCancelled(true);
                    }
                }
            }
            else if (projectile.getShooter() instanceof Wither) {
                final Wither wither = (Wither)projectile.getShooter();
                final TeamWither teamWither = (TeamWither)((CraftWither)wither).getHandle();
                if (e.getEntity() instanceof Player) {
                    final GamePlayer gamePlayer3 = GamePlayer.get(e.getEntity().getUniqueId());
                    if (teamWither.getGameTeam().isInTeam(gamePlayer3)) {
                        e.setCancelled(true);
                    }
                }
            }
            else if (projectile.getShooter() instanceof Entity && e.getEntity() instanceof Player && ((Entity)projectile.getShooter()).hasMetadata(MegaWalls.getMetadataValue())) {
                if (!(((Entity)projectile.getShooter()).getMetadata(MegaWalls.getMetadataValue()).get(0).value() instanceof GameTeam)) {
                    return;
                }
                final GameTeam gameTeam = (GameTeam)((Entity)projectile.getShooter()).getMetadata(MegaWalls.getMetadataValue()).get(0).value();
                if (gameTeam.isInTeam(GamePlayer.get(e.getEntity().getUniqueId()))) {
                    e.setCancelled(true);
                }
            }
        }
        else if (e.getDamager().hasMetadata(MegaWalls.getMetadataValue()) && e.getEntity() instanceof Player) {
            if (!(e.getDamager().getMetadata(MegaWalls.getMetadataValue()).get(0).value() instanceof GameTeam)) {
                return;
            }
            final GameTeam gameTeam3 = (GameTeam)e.getDamager().getMetadata(MegaWalls.getMetadataValue()).get(0).value();
            if (gameTeam3.isInTeam(GamePlayer.get(e.getEntity().getUniqueId()))) {
                e.setCancelled(true);
            }
        }
    }
    
    @EventHandler(priority = EventPriority.HIGHEST)
    public void onEntityRegainHealth(final EntityRegainHealthEvent e) {
        if (e.getEntityType() == EntityType.WITHER) {
            e.setCancelled(true);
            e.setAmount(0.0);
        }
    }
}
